#include "videocapturer.h"
#include"dlog.h"
#include"timesutil.h"
#include"avpublishtime.h"

VideoCapturer::VideoCapturer()
{

}

VideoCapturer::~VideoCapturer()
{
    if(_yuv_buf)
    {
        delete[] _yuv_buf;
    }
    if(_yuv_fp)
    {
        fclose(_yuv_fp);
    }
}

RET_CODE VideoCapturer::init(const Properties &properties)
{
    _video_test = properties.GetProperty("video_test", 0);
    _input_yuv_name = properties.GetProperty("input_yuv_name", "720x480_25fps_420p.yuv");
    _x = properties.GetProperty("x", 0);
    _y = properties.GetProperty("y", 0);
    _width = properties.GetProperty("width", 1920);
    _height = properties.GetProperty("height", 1080);
    _pixel_format = properties.GetProperty("pixel_format", 0);
    _fps = properties.GetProperty("fps", 25);
    _frame_duration = 1000.0 / _fps;    // 计算一帧的时长，单位毫秒

    // fix me，不应该硬编码 *1.5是因为固定YUV420p，如果格式不是YUV420p，那么就不是*1.5
    _yuv_buf_size = (_width + _width % 2) * (_height + _height % 2) * 1.5;// 一帧图片的字节大小
    _yuv_buf = new uint8_t[_yuv_buf_size];
    if(!_yuv_buf)
    {
        LogError("new _yuv_buf failed");
        return RET_ERR_OUTOFMEMORY;
    }
    // 打开yuv文件
    if(openYuvFile(_input_yuv_name.c_str()) != 0)
    {
        LogError("openYuvFile %s failed", _input_yuv_name.c_str());
        return RET_FAIL;
    }
    return RET_OK;
}

void VideoCapturer::loop()
{
    LogInfo("into");
    _yuv_total_duration = 0;
    _yuv_start_time = TimesUtil::GetTimeMillisecond();
    while(true)
    {
        if(_request_abort)
        {
            break;
        }
        if(readYuvFile(_yuv_buf, _yuv_buf_size) == 0)
        {
            if(!_is_first_frame)
            {
                _is_first_frame = true;
                LogInfo("%s: t%u", AVPublishTime::GetInstance()->getVInTag(),
                        AVPublishTime::GetInstance()->getCurrenTime());
            }
            if(_callbak)
            {
                _callbak(_yuv_buf, _yuv_buf_size);
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(2));
    }
    _request_abort = false;
    closeYuvFile();
    LogInfo("leave");
}

void VideoCapturer::addCallback(function<void (uint8_t *, int32_t)> callback)
{
    _callbak = callback;
}

int VideoCapturer::openYuvFile(const char *file_name)
{
    _yuv_fp = fopen(file_name, "rb");
    if(!_yuv_fp)
    {
        return -1;
    }
    return 0;

}

int VideoCapturer::readYuvFile(uint8_t *yuv_buf, int32_t yuv_buf_size)
{
    int64_t dif = TimesUtil::GetTimeMillisecond() - _yuv_start_time;
    if(_yuv_total_duration > dif)
    {
        return 1;
    }
    size_t ret = fread(yuv_buf, 1, yuv_buf_size, _yuv_fp);
    if(ret != (size_t)yuv_buf_size)
    {
        ret = fseek(_yuv_fp, 0, SEEK_SET);
        ret = fread(yuv_buf, 1, yuv_buf_size, _yuv_fp);
        if(ret != (size_t)yuv_buf_size)
        {
            LogError("readYuvFile failed");
            return -1;
        }
    }
    _yuv_total_duration += _frame_duration;
    return 0;
}

int VideoCapturer::closeYuvFile()
{
    if(_yuv_fp)
    {
        fclose(_yuv_fp);
    }
    return 0;
}
